# 获取脚本所在目录
$currentScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
$configFilePath = Join-Path -Path $currentScriptPath -ChildPath "deploy.json"
$winswExePath = Join-Path -Path $currentScriptPath -ChildPath "winsw.exe"
$downloadDir = Join-Path -Path $currentScriptPath -ChildPath "download"

# 默认配置
$defaultConfig = @{
    DownloadUrl = ""
    StartDllName = ""
    AppDirName = "app"
    Port = "8080"
    Environment = "Production"
    ProxyAddress = ""
    Updates = @{}
}

# 显示当前配置值并获取用户输入
function GetUserInput {
    param (
        [string]$prompt,
        [string]$currentValue
    )
    if ([string]::IsNullOrWhiteSpace($currentValue)) {
        return Read-Host "$prompt"
    } else {
        $input = Read-Host "$prompt [$currentValue]"
        if ($input -eq "/") {
            return ""
        } elseif ([string]::IsNullOrWhiteSpace($input)) {
            return $currentValue
        } else {
            return $input
        }
    }
}

# 定义函数
function Install-Service {
    if (-Not (Test-Path $configFilePath)) {
        Write-Output "配置文件不存在。"
        return
    }

    $appDirectory = Join-Path -Path $currentScriptPath -ChildPath $config.AppDirName
    $zipFileName = [System.IO.Path]::GetFileName($config.DownloadUrl)
    $zipFilePath = Join-Path -Path $downloadDir -ChildPath $zipFileName

    if (Test-Path $appDirectory) {
        Write-Output "找到部署目录，直接安装..."
    } elseif (Test-Path $zipFilePath) {
        Write-Output "找到本地部署包，正在解压..."
        Expand-Archive -Path $zipFilePath -DestinationPath $appDirectory -Force
        Write-Output "部署包已成功解压到 $appDirectory"
    } else {
        Write-Error "本地部署包不存在: $zipFilePath"
        return
    }

    if (-Not (Test-Path $winswExePath)) {
        Write-Error "winsw.exe 不存在"
        return
    }

    & $winswExePath install

    Write-Output "服务已安装"
}

function Start-Service {
    if (-Not (Test-Path $configFilePath)) {
        Write-Output "配置文件不存在。"
        return
    }

    if (-Not (Test-Path $winswExePath)) {
        Write-Error "winsw.exe 不存在"
        return
    }

    Write-Output "启动服务..."
    & $winswExePath start
    Write-Output "服务已启动。"
}

function Stop-Service {
    if (-Not (Test-Path $configFilePath)) {
        Write-Output "配置文件不存在。"
        return
    }

    if (-Not (Test-Path $winswExePath)) {
        Write-Error "winsw.exe 不存在"
        return
    }

    Write-Output "停止服务..."
    & $winswExePath stop
    Write-Output "服务已停止。"
}

function Uninstall-Service {
    if (-Not (Test-Path $configFilePath)) {
        Write-Output "配置文件不存在。"
        return
    }

    if (-Not (Test-Path $winswExePath)) {
        Write-Error "winsw.exe 不存在"
        return
    }

    Write-Output "卸载服务..."
    if ((& $winswExePath status) -match 'RUNNING') {
        & $winswExePath stop
    }
    & $winswExePath uninstall
    Write-Output "服务已卸载。"
}

function Update-Service {
    if (-Not (Test-Path $configFilePath)) {
        Write-Output "配置文件不存在。"
        return
    }

    $zipFileName = [System.IO.Path]::GetFileName($config.DownloadUrl)
    $zipFilePath = Join-Path -Path $downloadDir -ChildPath $zipFileName
    $appDirName = $config.AppDirName

    if (-Not (Test-Path $zipFilePath)) {
        Write-Error "更新包不存在: $zipFilePath"
        return
    }

    # 备份当前配置和应用目录
    $backupTime = Get-Date -Format "yyyyMMddHHmmss"
    $backupDir = Join-Path $currentScriptPath "backup_$backupTime"
    New-Item -ItemType Directory -Path $backupDir | Out-Null
    
    # 备份配置文件
    Copy-Item -Path $configFilePath -Destination $backupDir
    Copy-Item -Path (Join-Path $currentScriptPath "winsw.xml") -Destination $backupDir
    
    # 备份应用目录
    $appBackupDir = Join-Path $backupDir $config.AppDirName
    if (Test-Path $config.AppDirName) {
        Copy-Item -Recurse -Path $config.AppDirName -Destination $appBackupDir
    }
    
    Write-Output "已备份配置文件和应用程序到 $backupDir"
    
    # 计算校验和
    $zipHash = (Get-FileHash -Algorithm SHA256 -Path $zipFilePath).Hash
    Write-Output "部署包校验和: $zipHash"

    Write-Output "正在停止服务..."
    if ((& $winswExePath status) -match 'RUNNING') {
        & $winswExePath stop
    }

    Write-Output "正在解压覆盖应用目录..."
    try {
        Expand-Archive -Path $zipFilePath -DestinationPath $appDirName -Force
        if (-Not (Test-Path (Join-Path $appDirName $config.StartDllName))) {
            throw "解压部署包失败，未找到启动文件"
        }
        Write-Output "部署包已成功解压到 $appDirName"
    } catch {
        Write-Error "解压部署包失败: $_"
        
        # 回滚操作
        Write-Output "正在回滚到备份版本..."
        Copy-Item -Path (Join-Path $backupDir "deploy.json") -Destination $currentScriptPath -Force
        Copy-Item -Path (Join-Path $backupDir "winsw.xml") -Destination $currentScriptPath -Force
        Write-Output "已恢复配置文件"
        
        exit 1
    }

    Write-Output "正在启动服务..."
    & $winswExePath start
    if ($LASTEXITCODE -ne 0) {
        Write-Error "启动服务失败"
        exit 1
    }

    Write-Output "服务已更新。"
    Write-Output "部署包校验和: $zipHash"
}

function Update-Custom-Update {
    $scriptName = GetUserInput "请输入要执行的自定义更新名称"

    if (-Not ($config.Updates.PSObject.Properties.Name -contains $scriptName)) {
        Write-Error "未找到名为 $scriptName 的自定义更新配置。"
        return
    }

    $downloadUrl = $config.Updates.$scriptName.DownloadUrl
    $targetDir = $config.Updates.$scriptName.TargetDir

    $zipFileName = [System.IO.Path]::GetFileName($downloadUrl)
    $zipFilePath = Join-Path -Path $downloadDir -ChildPath $zipFileName

    if (-Not (Test-Path $zipFilePath)) {
        Write-Error "更新包不存在: $zipFilePath"
        return
    }

    # 检查目标目录是否存在
    if (Test-Path $targetDir) {
        Write-Output "正在清空目标目录..."
        Remove-Item -Recurse -Force -Path $targetDir\*
    } else {
        Write-Output "目标目录 $targetDir 不存在，跳过清空操作。"
    }

    Write-Output "正在解压到目标目录..."
    Expand-Archive -Path $zipFilePath -DestinationPath $targetDir -Force
    Write-Output "部署包已成功解压到 $targetDir"

    Write-Output "自定义更新完成。"
}

function Rollback-Service {
    # 查找最新的备份目录
    $backupDirs = Get-ChildItem -Path $currentScriptPath -Directory | Where-Object { $_.Name -match "^backup_" } | Sort-Object LastWriteTime -Descending
    
    if ($backupDirs.Count -eq 0) {
        Write-Error "没有可用的备份"
        return
    }

    $latestBackup = $backupDirs[0].FullName

    Write-Output "正在从备份恢复: $latestBackup"
    
    # 停止服务
    if ((& $winswExePath status) -match 'RUNNING') {
        & $winswExePath stop
    }

    try {
        # 恢复配置文件
        Copy-Item -Path (Join-Path $latestBackup "deploy.json") -Destination $currentScriptPath -Force
        Copy-Item -Path (Join-Path $latestBackup "winsw.xml") -Destination $currentScriptPath -Force
        
        # 恢复应用目录
        $appBackupDir = Join-Path $latestBackup $config.AppDirName
        if (Test-Path $appBackupDir) {
            Remove-Item -Recurse -Force -Path $config.AppDirName -ErrorAction SilentlyContinue
            Copy-Item -Recurse -Path $appBackupDir -Destination $config.AppDirName
        }
        
        Write-Output "已成功恢复备份"
    } catch {
        Write-Error "恢复备份失败: $_"
        exit 1
    }

    # 启动服务
    Write-Output "正在启动服务..."
    & $winswExePath start
    if ($LASTEXITCODE -ne 0) {
        Write-Error "启动服务失败"
        exit 1
    }

    Write-Output "服务已从备份恢复并启动"
}

# 循环执行操作
while ($true) {
    do {
        $Action = Read-Host "请输入操作 (install/start/stop/uninstall/update/update-c/rollback/exit)"
    } while ("install", "start", "stop", "uninstall", "update", "update-c", "rollback", "exit" -notcontains $Action)

    # 加载配置文件
    if (Test-Path $configFilePath) {
        try {
            $config = Get-Content -Path $configFilePath | ConvertFrom-Json
            # 确保 Updates 是一个 PSCustomObject
            if (-Not ($config.Updates -is [PSCustomObject])) {
                $config.Updates = [PSCustomObject]@{}
            }
        } catch {
            Write-Error "配置文件格式错误: $_"
            exit 1
        }
    } else {
        Write-Error "配置文件不存在，请先运行 generate.ps1 进行配置"
        exit 1
    }

    switch ($Action) {
        "install" {
            Install-Service
            break
        }
        "start" {
            Start-Service
            break
        }
        "stop" {
            Stop-Service
            break
        }
        "uninstall" {
            Uninstall-Service
            break
        }
        "update" {
            Update-Service
            break
        }
        "update-c" {
            Update-Custom-Update
            break
        }
        "rollback" {
            Rollback-Service
            break
        }
        "exit" {
            Write-Output "退出脚本。"
            exit 0
        }
    }

    # 重置 Action 以便下次循环
    $Action = $null
} 